package com.jiangsong.service;

import cn.hutool.core.date.DateUtil;
import com.jiangsong.entity.FeeRate;
import com.jiangsong.entity.FeeRateHis;
import com.jiangsong.entity.Product;
import com.jiangsong.mapper.FeeRateHisMapper;
import com.jiangsong.mapper.FeeRateMapper;
import com.jiangsong.mapper.ProductMapper;
import com.jiangsong.mq.MyMqSender;
import com.jiangsong.service.dto.QueryProductInput;
import com.jiangsong.utils.MultiplyQueryUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ProductService {

    @Autowired
    ProductMapper productMapper;

    @Autowired
    FeeRateMapper feeRateMapper;

    @Autowired
    MyMqSender myMqSender;

    @Autowired
    FeeRateHisMapper feeRateHisMapper;

    @Autowired
    private TransactionTemplate transactionTemplate;

    public List<Product> queryProductByAcc(String accNo) {

        log.info("test queryProductByAcc begin, accNo:{}", accNo);

        List<Product> productsOfThisAccNo = productMapper.getProductByAccNo(accNo);

        log.info("test queryProductByAcc begin, accNo:{}, productsOfThisAccNo:{}", accNo, productsOfThisAccNo);

        return productsOfThisAccNo;

    }

    public void createOneProduct(String accNo, String vendiNo, String date) {

        log.info("test createOneProduct begin, accNo:{}, vendiNo:{},date:{}", accNo, vendiNo, date);

        Product newPeoductInput = new Product();
        newPeoductInput.setAccNo(accNo);
        newPeoductInput.setBeginDate(date);
        newPeoductInput.setEndDate(date);
        newPeoductInput.setVendiNo(vendiNo);


        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {

                try {
                    int insertedNum = productMapper.insertOne(newPeoductInput);
                    log.info("test createOneProduct end, insertedNum:{}", insertedNum);

                    List<Product> productByAccNo = productMapper.getProductByAccNo(accNo);
                    log.info("test createOneProduct, 中间查询结果:{}", productByAccNo);
                    Assert.isTrue(insertedNum == 1, "新增product异常");

                } catch (Exception e) {
                    status.setRollbackOnly();
                    throw e;
                }
            }
        });

        // 事务提交后发送消息,允许失败,定时任务兜底
        myMqSender.sendMsg(accNo);
        log.info("test createOneProduct end, accNo:{}, vendiNo:{},date:{}", accNo, vendiNo, date);

    }


    public boolean createFeeRateWhenNewSignAccWithTransaction(String accNo) {
        log.info("test createFeeRateWhenNewSignAccWithTransaction start,待处理账号:{}", accNo);
        // 幂等处理
        List<FeeRate> feeRatesOfThisAcc = feeRateMapper.getFeeRatesByAccNo(accNo);
        if (!CollectionUtils.isEmpty(feeRatesOfThisAcc)) {
            log.info("test createFeeRateWhenNewSignAccWithTransaction end,该账号已经被处理过,跳出,账号:{}", accNo);
            return false;
        }

        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {

                try {
                    FeeRate feeRate = newFeeRate(accNo);
                    newFeeRateHis(feeRate);
                } catch (Exception e) {
                    status.setRollbackOnly();
                    throw e;
                }
            }
        });

        log.info("test createFeeRateWhenNewSignAccWithTransaction end,处理账号:{}", accNo);

        return true;
    }


    public boolean createFeeRateWhenNewSignAcc(String accNo) {
        log.info("test createFeeRateWhenNewSignAcc start,待处理账号:{}", accNo);
        // 幂等处理
        List<FeeRate> feeRatesOfThisAcc = feeRateMapper.getFeeRatesByAccNo(accNo);
        if (!CollectionUtils.isEmpty(feeRatesOfThisAcc)) {
            log.info("test createFeeRateWhenNewSignAcc end,该账号已经被处理过,跳出,账号:{}", accNo);
            return false;
        }

        FeeRate feeRate = newFeeRate(accNo);

        newFeeRateHis(feeRate);

        log.info("test createFeeRateWhenNewSignAcc end,处理账号:{}", accNo);
        return true;
    }

    private void newFeeRateHis(FeeRate feeRate) {
        FeeRateHis feeRateHis = new FeeRateHis();
        feeRateHis.setAccNo(feeRate.getAccNo());
        feeRateHis.setAmt(feeRate.getAmt());
        feeRateHis.setProjNo(feeRate.getProjNo());
        feeRateHis.setProjDesc(feeRate.getProjDesc());
        feeRateHis.setLevel(0);
        feeRateHis.setRate(feeRate.getRate());
        feeRateHis.setChargeDate(feeRate.getChargeDate());
        feeRateHis.setTraceId("0000000000001");
        feeRateHis.setKind(1);
        feeRateHis.setServNo("4I52");
        feeRateHis.setModifiedDesc("new fee rate when new product");

        Date date = DateUtil.offsetDay(DateUtil.date(), -1);
        // 使用 DateUtil.format() 方法将日期按照指定格式进行格式化
        String formattedDate = DateUtil.format(date, "yyyyMMdd");
        feeRateHis.setDate(formattedDate);

        log.info("test insertOneFeeRateHis begin, input:{}", feeRateHis);

        int insertedFeeRateHisNum = feeRateHisMapper.insertOne(feeRateHis);
        log.info("test insertOneFeeRateHis end, output:{}", insertedFeeRateHisNum);

        Assert.isTrue(insertedFeeRateHisNum == 1, "新增feeRateHis异常");
    }

    private FeeRate newFeeRate(String accNo) {
        FeeRate feeRate = new FeeRate();
        feeRate.setAccNo(accNo);
        feeRate.setProjNo("4114");
        feeRate.setProjDesc("4114-desc");
        feeRate.setAmt(new BigDecimal("0.3"));
        feeRate.setRate(null);
        Date date = DateUtil.date();
        // 使用 DateUtil.format() 方法将日期按照指定格式进行格式化
        String formattedDate = DateUtil.format(date, "yyyyMMdd");
        feeRate.setChargeDate(formattedDate);
        log.info("test insertOneFeeRate begin, input:{}", feeRate);
        int insertedFeeRateNum = feeRateMapper.insertOne(feeRate);
        log.info("test insertOneFeeRate end, output:{}", insertedFeeRateNum);
        Assert.isTrue(insertedFeeRateNum == 1, "新增feeRate异常");
        return feeRate;
    }

    public void queryAllProducts(String validFlag) {
        QueryProductInput queryProductInput = new QueryProductInput();
        queryProductInput.setValidFlag(validFlag);

        List<Product> ans = MultiplyQueryUtil.of(2, this::queryAllProductByPage)
                .initPageSize(3)
                .initQueryLimit(200)
                .execute(queryProductInput, this::getProductCount);
        System.out.println("最终结果长度:{}" + ans.size());
        System.out.println("最终结果为:{}" + ans);
        System.out.println("最终简单结果为" + ans.stream().map(Product::getAccNo).collect(Collectors.toList()));
    }

    public List<Product> queryAllProductByPage(QueryProductInput queryProductInput) {
        System.out.println("单次查询输入:{}" + queryProductInput);
        return productMapper.getProductByPage(queryProductInput);
    }

    public Integer getProductCount(QueryProductInput queryProductInput) {
        System.out.println("单次count查询输入:{}" + queryProductInput);
        Integer count = productMapper.getCount(queryProductInput);
        System.out.println("单次count查询输出:{}" + count);
        return count;
    }
}